
package com.yishe.config.db;

import com.alibaba.druid.pool.DruidDataSource;

import com.yishe.constant.DatabaseDialect;
import com.yishe.utils.AESBase64Util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Value;

import java.sql.SQLException;
import java.util.Properties;

@Slf4j
public class DataSourceConfig {

    ///////////////////// druid start 参数///////////////////////////////////////////////////
    @Value(value = "${spring.datasource.filters}")
    private String filters;
    @Value(value = "${spring.datasource.maxActive}")
    private String maxActive;
    @Value(value = "${spring.datasource.initialSize}")
    private String initialSize;
    @Value(value = "${spring.datasource.maxWait}")
    private String maxWait;
    @Value(value = "${spring.datasource.minIdle}")
    private String minIdle;
    @Value(value = "${spring.datasource.timeBetweenEvictionRunsMillis}")
    private String timeBetweenEvictionRunsMillis;
    @Value(value = "${spring.datasource.minEvictableIdleTimeMillis}")
    private String minEvictableIdleTimeMillis;
    @Value(value = "${spring.datasource.maxEvictableIdleTimeMillis}")
    private String maxEvictableIdleTimeMillis;
    @Value(value = "${spring.datasource.keepAlive}")
    private boolean keepAlive;
    @Value(value = "${spring.datasource.testWhileIdle}")
    private String testWhileIdle;
    @Value(value = "${spring.datasource.testOnBorrow}")
    private String testOnBorrow;
    @Value(value = "${spring.datasource.testOnReturn}")
    private String testOnReturn;
    @Value(value = "${spring.datasource.poolPreparedStatements}")
    private String poolPreparedStatements;
    @Value(value = "${spring.datasource.maxOpenPreparedStatements}")
    private String maxOpenPreparedStatements;
    @Value(value = "${spring.datasource.mysqlValidationQuery}")
    private String mysqlValidationQuery;
    @Value(value = "${spring.datasource.as400ValidationQuery}")
    private String as400ValidationQuery;
    ///////////////////// druid start 参数///////////////////////////////////////////////////
    /*** 加密的私钥密码串，用于 AESBase64Util 解密使用，属性文件配置中需要跟这个保持一致  **/

    private static String secretKey = AESBase64Util.DEFAULT_KEY;

    @Value(value = "${spring.datasource.removeAbandoned}")
    private boolean removeAbandoned;
    @Value(value = "${spring.datasource.removeAbandonedTimeout}")
    private int removeAbandonedTimeout;
    @Value(value = "${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private int maxPoolPreparedStatementPerConnectionSize;
    @Value(value = "${spring.datasource.logAbandoned}")
    private boolean logAbandoned;


    /**
     * 分布式事务参数 atomikos end
     ***/

    @Value(value = "${spring.datasource.validationQueryTimeout:3}")
    private int validationQueryTimeout;

    @Value(value = "${mybaits.global.properties.dataBase.db2PBSEC:PBSEC6C}")
    private String db2PBSEC;


    protected void initDataSource(DruidDataSource druidDataSource, String dialect) {
        log.info("DataSourceConfig Param filters is :{}", filters);
        log.info("DataSourceConfig Param maxActive is :{}", maxActive);
        log.info("DataSourceConfig Param initialSize is :{} ", initialSize);
        log.info("DataSourceConfig Param maxWait is :{} ", maxWait);
        log.info("DataSourceConfig Param minIdle is :{}", minIdle);
        log.info("DataSourceConfig Param timeBetweenEvictionRunsMillis is :{}", timeBetweenEvictionRunsMillis);
        log.info("DataSourceConfig Param minEvictableIdleTimeMillis is :{}", minEvictableIdleTimeMillis);
        log.info("DataSourceConfig Param maxEvictableIdleTimeMillis is :{}", maxEvictableIdleTimeMillis);
        log.info("DataSourceConfig Param keepAlive is :{}", keepAlive);
        log.info("DataSourceConfig Param testWhileIdle is :{}", testWhileIdle);
        log.info("DataSourceConfig Param testOnBorrow is :{}", testOnBorrow);
        log.info("DataSourceConfig Param testOnReturn is :{}", testOnReturn);
        log.info("DataSourceConfig Param poolPreparedStatements is :{}", poolPreparedStatements);
        log.info("DataSourceConfig Param maxOpenPreparedStatements is :{}", maxOpenPreparedStatements);
        log.info("DataSourceConfig Param mysqlValidationQuery is :{}", mysqlValidationQuery);
        log.info("DataSourceConfig Param as400ValidationQuery is :{}", as400ValidationQuery);
        log.info("DataSourceConfig Param removeAbandoned is :{}", removeAbandoned);
        log.info("DataSourceConfig Param removeAbandonedTimeout is :{}", removeAbandonedTimeout);
        log.info("DataSourceConfig Param maxPoolPreparedStatementPerConnectionSize is :{}", maxPoolPreparedStatementPerConnectionSize);
        log.info("DataSourceConfig Param logAbandoned is :{}", logAbandoned);
        log.info("DataSourceConfig Param validationQueryTimeout is :{}", validationQueryTimeout);


        druidDataSource.setMaxActive(StringUtils.isNotBlank(maxActive) ? Integer.parseInt(maxActive) : 10);
        druidDataSource.setInitialSize(StringUtils.isNotBlank(initialSize) ? Integer.parseInt(initialSize) : 1);
        druidDataSource.setMaxWait(StringUtils.isNotBlank(maxWait) ? Integer.parseInt(maxWait) : 60000);
        druidDataSource.setMinIdle(StringUtils.isNotBlank(minIdle) ? Integer.parseInt(minIdle) : 3);
        druidDataSource.setTimeBetweenEvictionRunsMillis(StringUtils.isNotBlank(timeBetweenEvictionRunsMillis) ? Integer.parseInt(timeBetweenEvictionRunsMillis) : 60000);
        druidDataSource.setMinEvictableIdleTimeMillis(StringUtils.isNotBlank(minEvictableIdleTimeMillis) ? Integer.parseInt(minEvictableIdleTimeMillis) : 300000);
        druidDataSource.setMaxEvictableIdleTimeMillis(StringUtils.isNotBlank(maxEvictableIdleTimeMillis) ? Integer.parseInt(maxEvictableIdleTimeMillis) : 900000);
        druidDataSource.setKeepAlive(keepAlive ? keepAlive : true);
        druidDataSource.setTestWhileIdle(StringUtils.isNotBlank(testWhileIdle) ? Boolean.parseBoolean(testWhileIdle) : true);
        druidDataSource.setTestOnBorrow(StringUtils.isNotBlank(testOnBorrow) ? Boolean.parseBoolean(testOnBorrow) : false);
        druidDataSource.setTestOnReturn(StringUtils.isNotBlank(testOnReturn) ? Boolean.parseBoolean(testOnReturn) : false);
        druidDataSource.setPoolPreparedStatements(StringUtils.isNotBlank(poolPreparedStatements) ? Boolean.parseBoolean(poolPreparedStatements) : true);
        druidDataSource.setMaxOpenPreparedStatements(StringUtils.isNotBlank(maxOpenPreparedStatements) ? Integer.parseInt(maxOpenPreparedStatements) : 20);
        druidDataSource.setRemoveAbandoned(removeAbandoned);
        druidDataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        druidDataSource.setLogAbandoned(logAbandoned);
        druidDataSource.setValidationQueryTimeout(validationQueryTimeout);

        if (DatabaseDialect.MYSQL.equals(dialect)) {
            druidDataSource.setValidationQuery(StringUtils.isNotBlank(mysqlValidationQuery) ? mysqlValidationQuery : "select 'x'");
        } else if (DatabaseDialect.DB2.equals(dialect)) {
            druidDataSource.setValidationQuery("select 1 from sysibm.sysdummy1");
        } else if (DatabaseDialect.AS400.equals(dialect)) {
            druidDataSource.setValidationQuery(StringUtils.isNotBlank(as400ValidationQuery) ? as400ValidationQuery : "select 1 from sysibm.sysdummy1");
        } else if (DatabaseDialect.SQLSERVER.equals(dialect)) {
            druidDataSource.setValidationQuery("select 'x'");
        } else if (DatabaseDialect.Oracle.equals(dialect)) {
            druidDataSource.setValidationQuery("select 1 from dual ");
        } else {
            druidDataSource.setValidationQuery("select 'x'");
        }
        try {
            druidDataSource.setFilters(StringUtils.isNotBlank(filters) ? filters : "stat, wall");
            // 初始化连接池
            druidDataSource.init();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    /**
     * 解密数据库密码
     *
     * @param secretPassword 加密后的数据库密码字符串
     * @return
     */
    public String decryptionPassword(String secretPassword) throws Exception {
        String passwordStr = "";
        if (StringUtils.isNotBlank(secretKey)) {
            // 密码解密
            passwordStr = AESBase64Util.decrypt(secretPassword, StringUtils.trim(secretKey));
            log.info("数据库密码解密成功!");
        } else {
            String error = "配置中心（或配置属性文件）没有配置属性（sunline.secret.key），请重新确认。";
            log.warn(error);
            throw new Exception(error);
        }

        return passwordStr;
    }

    /**
     * @Description: [设置mybaits 全局变量]
     * @author lh
     * @CreateDate: 2020/9/29 14:17
     * @update: [序号][日期YYYY-MM-DD] [更改人姓名][变更描述]
     */
    public void setProperties(SqlSessionFactoryBean sqlSessionFactoryBean) {
        Properties properties = new Properties();
        properties.setProperty("global_db2PBSEC", db2PBSEC);
        log.info("设置mybaits全局变量[{}]",properties);
        sqlSessionFactoryBean.setConfigurationProperties(properties);
    }

}
